From a387f16b05ebb5e46709b201925c3eddf23e3aab Mon Sep 17 00:00:00 2001 From: oliskoli Date: Sun, 15 Apr 2007 19:46:05 +0000 Subject: [PATCH] Add new format "g7towin". This format can read data files (.g7t) from G7ToWin. --- g7towin.c | 541 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 g7towin.c diff --git a/g7towin.c b/g7towin.c new file mode 100644 index 000000000..41609778b --- /dev/null +++ b/g7towin.c @@ -0,0 +1,541 @@ +/* + + Support for G7ToWin data files (.g7t), + Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + +/* + History: + 04/07/2007: start programming +*/ + +#include "defs.h" +#include "csv_util.h" +#include "garmin_fs.h" +#include "garmin_tables.h" +#include "jeeps/gpsmath.h" +#include "strptime.h" + +#include + +#if CSVFMTS_ENABLED + +#define MYNAME "g7towin" + +#define G7T_HEADER "Version 2:G7T" + +static gbfile *fin; +static grid_type grid; +static int datum; +static gpsdata_type mode; +static double altf; +static int gardown; +static int event_ct; + +static +arglist_t g7towin_args[] = { + ARG_TERMINATOR +}; + +#define WAYPT__OFS 0x00000 +#define TRKPT__OFS 0x01000 + +#define WPT_c0_OFS 0x0c000 +#define WPT_c1_OFS 0x0c100 +#define WPT_c2_OFS 0x0c200 +#define WPT_c3_OFS 0x0c300 +#define WPT_c4_OFS 0x0c400 +#define WPT_c5_OFS 0x0c500 +#define WPT_c6_OFS 0x0c600 +#define WPT_c7_OFS 0x0c700 +#define WPT_c8_OFS 0x0c800 +#define WPT_cA_OFS 0x0cA00 +#define WPT_cB_OFS 0x0cB00 +#define WPT_cC_OFS 0x0cC00 +#define WPT_cD_OFS 0x0cD00 + +static void +parse_line(char *buff, int index, const char *delimiter, waypoint *wpt) +{ + char *cin; + garmin_fs_p gmsd = GMSD_FIND(wpt); + + while ((cin = csv_lineparse(buff, delimiter, "", index++))) { + + buff = NULL; + cin = lrtrim(cin); + + if ((*cin == '\0') || + (strcmp(cin, "INF") == 0) || + (strcmp(cin, "1e25") == 0) || + (strcmp(cin, "1.0e25") == 0)) continue; + + switch(index) { + + int categories, dyn; + struct tm tm; + char *cerr; + + case TRKPT__OFS + 1: + cin += parse_coordinates(cin, datum, grid, + &wpt->latitude, &wpt->longitude, MYNAME); + while (isspace(*cin)) cin++; + + memset(&tm, 0, sizeof(tm)); + cerr = strptime(cin, "%a %b %d %H:%M:%S %Y", &tm); + if (cerr == NULL) { + fatal(MYNAME ": Unable to convert date (%s)!\n", cin); + } + wpt->creation_time = mkgmtime(&tm); + break; + + case WAYPT__OFS + 1: + wpt->description = xstrdup(cin); + break; + + case WAYPT__OFS + 2: + wpt->icon_descr = gt_find_desc_from_icon_number( + atoi(cin), PCX, &dyn); + wpt->wpt_flags.icon_descr_is_dynamic = dyn; + break; + + case WAYPT__OFS + 4: + if (strcmp(cin, "S+C") == 0) { + GMSD_SET(display, gt_display_mode_symbol_and_comment); + } + else if (strcmp(cin, "S") == 0) { + GMSD_SET(display, gt_display_mode_symbol); + } + else if (strcmp(cin, "S+N") == 0) { + GMSD_SET(display, gt_display_mode_symbol_and_name); + } + break; + + case WPT_cA_OFS + 1: + case WPT_c1_OFS + 1: + if (wpt->shortname) xfree(wpt->shortname); + wpt->shortname = xstrdup(cin); + break; + + case WPT_cA_OFS + 4: + case WPT_c4_OFS + 2: + GMSD_SETSTR(city, cin); + break; + + case WPT_cA_OFS + 5: + case WPT_c4_OFS + 3: + GMSD_SETSTR(state, cin); + break; + + case WPT_cA_OFS + 6: + case WPT_c4_OFS + 4: + GMSD_SETSTR(cc, cin); + break; + + case WPT_cB_OFS + 1: + case WPT_c6_OFS + 2: + GMSD_SETSTR(facility, cin); + break; + + case WPT_cB_OFS + 2: + case WPT_c6_OFS + 3: + GMSD_SETSTR(addr, cin); + break; + + case WPT_cB_OFS + 3: /*cross road */ + case WPT_c6_OFS + 4: + GMSD_SETSTR(cross_road, cin); + break; + + case TRKPT__OFS + 2: /* altitude */ + case WPT_cC_OFS + 1: + case WPT_c5_OFS + 1: + case WPT_c8_OFS + 1: + wpt->altitude = altf * atof(cin); + break; + + case TRKPT__OFS + 3: /* depth */ + case WPT_cC_OFS + 2: + case WPT_c5_OFS + 2: + case WPT_c8_OFS + 2: + GMSD_SET(depth, altf * atof(cin)); + break; + + case TRKPT__OFS + 10: /* temperature */ + if (*cin == '|') cin++; /* in track points */ + if (strcmp(cin, "1e25") == 0) break; + if (strcmp(cin, "1.0e25") == 0) break; + /* !!! NO BREAK !!! */ + case WPT_cD_OFS + 1: + case WPT_cB_OFS + 6: + GMSD_SET(temperature, atof(cin)); + break; + + case WAYPT__OFS + 6: /* proximity */ + case WPT_cD_OFS + 2: + GMSD_SET(proximity, atof(cin)); + break; + + case WPT_cB_OFS + 5: + case WPT_cD_OFS + 3: + categories = atoi(cin); + if (categories != 0) + GMSD_SET(category, atoi(cin)); + break; + +#if 0 + +/* currently unused */ + + case TRKPT__OFS + 5: /* distance from previous point */ + case TRKPT__OFS + 6: /* distance from segment start */ + case TRKPT__OFS + 7: /* distance from start */ + case TRKPT__OFS + 8: /* velocity from previous point */ + case TRKPT__OFS + 9: /* time (in seconds) from previous point */ + break; + + case WAYPT__OFS + 3: /* ignore color */ + break; + + case WAYPT__OFS + 5: /* always '0' */ + break; + + case TRKPT__OFS + 4: + if (case_ignore_strcmp(cin, "FT") == 0) ; + else if (case_ignore_strcmp(cin, "M") == 0) ; + else if (case_ignore_strcmp(cin, "SM") == 0) ; + else if (case_ignore_strcmp(cin, "NM") == 0) ; + else if (case_ignore_strcmp(cin, "KM") == 0) ; + break; + + case WPT_cB_OFS + 4: /* unknown (datatype) */ + break; + + case WPT_cC_OFS + 3: /* waypt_class (always FF) */ + break; + + case WPT_cC_OFS + 4: /* class & subclass */ + case WPT_cC_OFS + 5: + case WPT_cC_OFS + 6: + case WPT_cC_OFS + 7: + case WPT_cC_OFS + 8: + case WPT_cC_OFS + 9: + case WPT_cC_OFS + 10: + case WPT_cC_OFS + 11: + case WPT_cC_OFS + 12: + case WPT_cC_OFS + 13: + case WPT_cC_OFS + 14: + case WPT_cC_OFS + 15: + case WPT_cC_OFS + 16: + case WPT_cC_OFS + 17: + case WPT_cC_OFS + 18: + case WPT_cC_OFS + 19: + case WPT_cC_OFS + 20: + case WPT_cC_OFS + 21: + break; + + case WPT_cC_OFS + 22: + /* distance */ + break; +#endif + } + } +} + +static waypoint * +parse_waypt(char *buff) +{ + char *cin, *cerr; + int i; + struct tm tm; + waypoint *wpt; + garmin_fs_p gmsd; + + wpt = waypt_new(); + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + + if (gardown) + cin = buff + 6; + else + cin = buff + 15; + + while (isspace(*cin)) cin--; + if (cin >= buff) + wpt->shortname = xstrndup(buff, cin - buff + 1); + + if (gardown) + buff += 7; + else + buff += 16; + + buff += parse_coordinates(buff, datum, grid, + &wpt->latitude, &wpt->longitude, MYNAME); + while (isspace(*buff)) buff++; + + memset(&tm, 0, sizeof(tm)); + cerr = strptime(buff, "%a %b %d %H:%M:%S %Y", &tm); + if (cerr == NULL) + fatal(MYNAME ": Unable to convert date (%s)!\n", buff); + wpt->creation_time = mkgmtime(&tm); + + /* go over time stamp */ + i = 5; + while (buff && i) { + i--; + buff = strchr(buff, ' '); + if (buff) buff++; + } + if (gardown && (buff == NULL)) return wpt; + is_fatal((buff == NULL), MYNAME ": Incomplete waypoint line!"); + + while (isspace(*buff)) buff++; + + parse_line(buff, WAYPT__OFS, "^", wpt); + + return wpt; +} + +static waypoint * +parse_trkpt(char *buff) +{ + garmin_fs_p gmsd; + waypoint *wpt; + + wpt = waypt_new(); + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + + parse_line(buff, TRKPT__OFS, ";", wpt); + + return wpt; +} + +/* + * parse_categories is currently only a dummy procedure. + * w'll need a central storage with binding to the module + * which has established a list of category names. + */ + +static void +parse_categories(char *buff) +{ + char *cin; + int cat = 0; + + while ((cin = csv_lineparse(buff, ",", "", cat++))) { + gbuint16 cx; + + buff = NULL; + + cin = lrtrim(cin); + if (*cin == 0) continue; + + garmin_fs_convert_category(cin, &cx); + } +} + + +/* main functions */ + +static void +rd_init(const char *fname) +{ + fin = gbfopen(fname, "rb", MYNAME); + + gardown = 1; + mode = wptdata; + grid = grid_lat_lon_dmm; + datum = DATUM_WGS84; + altf = 1; + event_ct = 0; +} + +static void +rd_deinit(void) +{ + gbfclose(fin); +} + +static void +data_read(void) +{ + char *buff; + int line = 0; + waypoint *wpt = NULL; + waypoint *prev = NULL; + route_head *head = NULL; + + while ((buff = gbfgetstr(fin))) { + char *cin = buff; + char *cdata; + + line++; + + cin = lrtrim(buff); + if (!*cin) continue; + + cdata = cin+1; + while (! isspace(*cdata)) cdata++; + while (isspace(*cdata)) cdata++; + if (! *cdata) continue; + + switch(*cin) { + + case '#': /* comment */ + break; + + case 'A': + if (case_ignore_strncmp(cdata, "Meter", 5) == 0) + altf = 1.0; + else if (case_ignore_strncmp(cdata, "Feet", 4) == 0) + altf = FEET_TO_METERS(1.0); + break; + + case 'C': /* categories */ + parse_categories(cdata); + break; + + case 'D': + datum = gt_lookup_datum_index(cdata, MYNAME); + break; + + case 'I': /* event point */ + wpt = waypt_new(); + cdata += parse_coordinates(cdata, datum, grid, + &wpt->latitude, &wpt->longitude, MYNAME); + xasprintf(&wpt->shortname, "Event%d", ++event_ct); + while (isspace(*cdata)) cdata++; + if (*cdata == ';') { + int dyn; + + cdata++; + wpt->icon_descr = gt_find_desc_from_icon_number( + atoi(cdata), PCX, &dyn); + wpt->wpt_flags.icon_descr_is_dynamic = dyn; + } + waypt_add(wpt); + break; + + case 'M': + grid = gt_lookup_grid_type(cdata, MYNAME); + break; + + case 'P': /* proximity waypoint */ + case 'W': /* normal waypoint */ + wpt = parse_waypt(cdata); + prev = wpt; + if (wpt) { + if (mode == rtedata) + route_add_wpt(head, wpt); + else + waypt_add(wpt); + } + break; + + case 'c': /* additional lines */ + switch(*(cin+1)) { + int index; + + case 'A': case 'B': + case 'C': case 'D': + + index = WPT_cA_OFS + ((*(cin+1) - 'A') * 256); + parse_line(cdata, index, "|", wpt); + break; + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': + + index = WPT_c0_OFS + ((*(cin+1) - '0') * 256); + parse_line(cdata, index, ";", wpt); + break; + + case 'L': + waypt_add_url(wpt, xstrdup(cdata), NULL); + break; + + default: + break; + } + break; + + case 'N': /* track log header */ + mode = trkdata; + head = route_head_alloc(); + cdata = strchr(cdata, '-'); + if (cdata) { + while (isspace(*cdata)) cdata++; + if (*cdata) { + char *s; + s = strrchr(cdata, ','); + if (s) { + *s = '\0'; + s = strrchr(cdata, ','); + if (s) { + *s = '\0'; + head->rte_name = xstrdup(cdata); + } + } + } + } + track_add_head(head); + break; + + case 'R': /* route header */ + mode = rtedata; + head = route_head_alloc(); + cdata += 3; /*skip route number */ + if (*cdata) head->rte_name = xstrdup(cdata); + route_add_head(head); + break; + + case 'T': + wpt = parse_trkpt(cdata); + if (wpt) track_add_wpt(head, wpt); + break; + + case 'V': + if (strcmp(cin, G7T_HEADER) != 0) { + fatal(MYNAME ": Invalid version or invalid file!\n"); + } + gardown = 0; + break; + + default: + break; + } + } +} + +/* --------------------------------------------------------------------------- */ + +ff_vecs_t g7towin_vecs = { + ff_type_file, + { ff_cap_read, ff_cap_read, ff_cap_read }, + rd_init, + NULL, + rd_deinit, + NULL, + data_read, + NULL, + NULL, + g7towin_args, + CET_CHARSET_MS_ANSI, 0 +}; + +#endif /* CSVFMTS_ENABLED */ -- 2.30.2